package com.googlecode.bip.chart.applet;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import cx.ath.choisnet.io.SerializableHelper;

/**
 * com.googlecode.bip.chart.applet.ChartAppletServlet
 *
 */
public class ChartAppletServlet extends HttpServlet
{
    private final static transient Logger logger = Logger.getLogger( ChartAppletServlet.class );
    private final static long serialVersionUID = 1L;
    public final static String CONTEXT_MAP = "SERVLET_UID_MAP";

    @Override
    public void init( ServletConfig servletConfig )
    {
    }

    @Override
    public void service(
        final HttpServletRequest    request,
        final HttpServletResponse   response
        )
        throws IOException
    {
        final String uId = request.getParameter( "UID" );
        logger.info( "UID = " + uId );

        JFreeChart chart = getItem( getServletContext(), uId );
        logger.info( "chart = " + chart );

        if( chart == null ) {
            logger.warn( "*** No chart found for UID: " + uId );

            // Provide a fake chart
            PieDataset datas = new DefaultPieDataset();

            chart = ChartFactory.createPieChart(
                    "No values for " + uId,
                    datas,
                    true,
                    true,
                    Locale.getDefault()
                    );
            logger.info( "Provide a fake chart = " + chart );
            }

        sendObject( chart, response );
    }

    protected void sendObject(
        final Serializable          object,
        final HttpServletResponse   response
        )
        throws IOException
    {
        final String mimeType = "java/bin";

        response.setHeader( "Content-Type", mimeType );

        final BufferedOutputStream  bos     = new BufferedOutputStream( response.getOutputStream());
        final byte[]                bytes   = SerializableHelper.toByteArray( object );

        logger.info( "sendObject length: " + bytes.length );

        response.setContentLength( bytes.length );
        bos.write( bytes, 0, bytes.length );

        bos.flush();
        bos.close();
    }

    /**
     *
     * @param <T>
     * @param context
     * @param object
     * @return
     */
    public final static <T> String putItem(
        final ServletContext context,
        final T object
        )
    {
        String uid = UUID.randomUUID().toString();

        putItem( context, uid, object );

        return uid;
    }

    /**
     *
     * @param <T>
     * @param context
     * @param uid
     * @param object
     */
    private final static <T> void putItem(
        final ServletContext    context,
        final String            uid,
        final T                 object
        )
    {
        final Map<String,T> map = getMap( context );

        map.put( uid, object );
    }

    /**
     *
     * @param <T>
     * @param context
     * @param uid
     * @return
     */
    public final static <T> T getItem(
        final ServletContext    context,
        final String            uid
        )
    {
        final Map<String,T> map = getMap( context );

        return map.get( uid );
    }

    /**
    *
    * @param <T>
    * @param context
    * @param uid
    * @return
    */
   public final static <T> T removeItem(
       final ServletContext    context,
       final String            uid
       )
   {
       final Map<String,T> map = getMap( context );

       return map.remove( uid );
   }

    /**
     *
     * @param <T>
     * @param context
     * @return
     */
    private final static <T> Map<String,T> getMap( final ServletContext context )
    {
        @SuppressWarnings("unchecked")
        Map<String,T> map = Map.class.cast( context.getAttribute( CONTEXT_MAP ) );

        if( map == null ) {
            map = setMap( context );
            }

        return map;
    }

    private final static <T> Map<String,T> setMap( final ServletContext context )
    {
        Map<String,T> map = new HashMap<String,T>();

        context.setAttribute( CONTEXT_MAP, map );

        return map;
    }

}
